﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace NetworkingLibrary.Utilities
{
    public static class Utilities
    {
        public static void CheckFlowRate(Clients.IClient TheClient)
        {
            if (TheClient.LastSendTime.AddMilliseconds(TheClient.MaxFlowRate) >= DateTime.Now)
            {
                System.Threading.Thread.Sleep((int)TheClient.MaxFlowRate);
            }
            TheClient.LastSendTime = DateTime.Now;
        }

        //Default set to Number of bytes for a 32-bit interger
        const int MessageLengthBytes = 4;

        public static byte[] ToBytes(object TheObj)
        {
            try
            {
                BinaryFormatter Form = new BinaryFormatter();
                MemoryStream Mr = new MemoryStream();
                Form.Serialize(Mr, TheObj);
                return Mr.ToArray();
            }
            catch
            {
            }
            return null;
        }
        public static object FromBytes(byte[] Buffer)
        {
            try
            {
                BinaryFormatter Form = new BinaryFormatter();
                MemoryStream Mr = new MemoryStream(Buffer);
                return Form.Deserialize(Mr);
            }
            catch
            {
            }
            return null;
        }

        internal static byte[] FormMessage(byte[] OrigBytes)
        {
            try
            {
                byte[] ActualLengthBytes = BitConverter.GetBytes(OrigBytes.Length);
                if (ActualLengthBytes.Length > MessageLengthBytes)
                {
                    throw new ArgumentException("Message too long!");
                }
                byte[] FinalBytes = new byte[OrigBytes.Length + MessageLengthBytes];
                ActualLengthBytes.CopyTo(FinalBytes, 0);
                OrigBytes.CopyTo(FinalBytes, MessageLengthBytes);

                return FinalBytes;
            }
            catch
            {
            }
            return OrigBytes;
        }

        internal static List<byte[]> GetAllMessages(byte[] OrigBytes)
        {
            List<byte[]> TheMessages = new List<byte[]>();
            List<byte[]> StartMessages = RetrieveMessage(OrigBytes);
            if (StartMessages.Count >= 2)
            {
                while (StartMessages.Count >= 2)
                {
                    StartMessages = RetrieveMessage(StartMessages[1]);
                    if (StartMessages.Count > 0)
                    {
                        TheMessages.Add(StartMessages[0]);
                    }
                }
            }
            else if(StartMessages.Count > 0)
            {
                TheMessages.Add(StartMessages[0]);
            }
            return TheMessages;
        }

        private static List<byte[]> RetrieveMessage(byte[] AllBytes)
        {
            List<byte[]> TheArray = new List<byte[]>(1);
            try
            {
                List<byte> LengthBytes = AllBytes.Take(MessageLengthBytes).ToList();
                
                try
                {
                    int TheLength = BitConverter.ToInt32(LengthBytes.ToArray(), 0);
                    byte[] OrigBytes = new byte[TheLength];
                    for (int i = 0; i < TheLength; i++)
                    {
                        OrigBytes[i] = AllBytes[i + MessageLengthBytes];
                    }
                    TheArray.Add(OrigBytes);
                    byte[] LeftOverBytes = new byte[(AllBytes.Length - (TheLength + MessageLengthBytes))];
                    if (LeftOverBytes.Length > 0)
                    {
                        AllBytes.CopyTo(LeftOverBytes, (TheLength + MessageLengthBytes));
                        TheArray.Add(LeftOverBytes);
                    }
                }
                catch
                {
                }
                return TheArray;
            }
            catch
            {
            }
            TheArray.Add(AllBytes);
            return TheArray;
        }
    }
}
